/**
 * Created by John on 2016/7/25.
 */
var demo = new Sample();
demo.foo1(1);
demo.foo2(2);
demo.foo3(3);
demo.sort();
demo.on();
demo.partialFunction();
demo.difficulty();
demo.publishAndSubscribe();
demo.eventHook();
demo.inheritEventsModule();
demo.eventQueueAvalanche();
demo.lockStatus();
demo.eventQueue();
demo.variableSentry();
demo.partialDerivatives();
demo.manyForOne();
demo.proxy();
demo.after();
demo.backbone();
demo.errorEventProxyOld();
demo.errorEventProxy();

function Sample() {
    this.foo1 = function (x) {
        return x;
    };

    this.foo2 = function (x) {
        return function () {
            return x
        };
    };

    this.foo3 = function (x, bar) {
        return bar(x);
    };

    this.sort = function () {
        var points = [40, 100, 1, 5, 25, 10];
        points.sort(function (a, b) {
            return a - b;
        })
    };

    this.on = function () {
        var events = require('events');
        var emitter = new events.EventEmitter();
        emitter.on('event_foo', function () {
            // TODO
        });
    };

    this.partialFunction = function () {
        function isStringOrFunction() {
            var toString = Object.prototype.toString;
            var isString = function (obj) {
                return toString.call(obj) == '[object string]';
            };
            var isFunction = function (obj) {
                return toString.call(obj) == '[object Function]';
            };
        }

        function isType() {
            var toString = Object.prototype.toString;
            var isType = function (type) {
                return function (obj) {
                    return toString.call(obj) == '[object' + type + ']';
                };
            };

            var isString = isType('String');
            var isFunction = isType('Function');
        }

        function after() {
            _.fater = function (times, func) {
                if (times <= 0) {
                    return func();
                }

                return function () {
                    if (--times < 1) {
                        return func.apply(this, arguments);
                    }
                }
            };
        }
    };

    this.difficulty = function () {
        function exception() {
            try {
                JSON.parse(josn);
            } catch (e) {
                // TODO
            }
        }

        function exceptionHandling() {
            function async() {
                var async = function (callback) {
                    process.nextTick(callback);
                }
            }

            try {
                async(callback);
            } catch (e) {
                // TODO
            }

            async(function (err, results) {
                // TODO
            });
        }

        function exceptionHandlingSpecification() {
            var async = function (callback) {
                process.nextTick(function () {
                    var results = something;
                    if (err) {
                        return callback(err);
                    }
                    callback(null, results);
                });
            };
        }

        function exceptionHandlingWarning() {
            try {
                req.body = JSON.parse(buf, options.reviver);
                callback();
            } catch (e) {
                err.body = buf;
                err.status = 400;
                callback(err);
            }
        }

        function execptionHandingAllRight() {
            try {
                req.body = JSON.parse(buf, options.reviver);
            } catch (e) {
                err.body = buf;
                err.status = 400;
                return callback(err);
            }
            callback();
        }

        function nestingLevelTooDeep() {
            $(selector).click(function (e) {
                // TODO
            });
            $(selector).change(function (e) {
                // TODO
            });
        }

        function tooMuchCallback() {
            var fs = require('fs');
            var path = require('path');
            fs.readdir(path.join(__dirname, '..'), function (err, files) {
                files.forEach(function (filename, index) {
                    fs.readFile(filename, 'utf-8', function (err, file) {
                        // TODO
                    });
                });
            });
        }

        function blockCoding() {
            // TODO
            var start = new Date();
            while (new Date() - start < 1000) {
                // TODO
            }
        }
    };

    this.publishAndSubscribe = function () {
        var emitter = require('events').EventEmiter();
        emitter.on('event1', function (message) {
            console.log(message);
        });
        emitter.emit('event1', 'I am message!');
    };

    this.eventHook = function () {
        var http = require('http');
        var options = {
            host: 'www.baidu.com',
            port: 80,
            path: 'upload',
            method: 'POST'
        };
        var req = http.request(options, function (res) {
            console.log('STATUS: ' + res.statusCode);
            console.log("HEADERS: " + JSON.stringify(res.headers));
            res.on('data', function (chunk) {
                console.log('BODY: ' + chunk);
            });
            res.on('end', function () {
                // TODO
            });
        });
        req.on('error', function (e) {
            console.log('problem with request: ' + e.message);
        });
        req.write('data\n');
        req.write('data\n');
        req.end();
    };

    this.inheritEventsModule = function () {
        var util = require('util');
        var events = require('events');

        function Stream() {
            events.EventEmitter.call(this);
        }

        util.inherits(Strem, events.EventEmitter);
    };

    this.eventQueueAvalanche = function () {
        /*db connect to database*/
        var db = null;
        var select = function (callback) {
            db.select('SQL', function (results) {
                callback(results);
            });
        }
    };

    this.lockStatus = function () {
        var status = 'ready';
        /*db connect to database*/
        var db = null;
        var slect = function (callback) {
            if (status == 'ready') {
                status = 'pending';
                db.select('SQL', function (results) {
                    status = 'ready';
                    callback(results);
                });
            }
        }
    };

    this.eventQueue = function () {
        var events = require('events');
        var proxy = new events.EventEmitter();
        var status = 'ready';
        /*db connect to database*/
        var db = null;
        var slect = function (callback) {
            proxy.once('selected', callback);
            if (status == 'ready') {
                status = 'pending';
                db.select('SQL', function (results) {
                    proxy.emit('selected', results);
                    status = 'ready';
                });
            }
        }
    };

    this.variableSentry = function () {
        var count = 0;
        var results = {};
        var done = function (key, value) {
            results[key] = value;
            count++;
            if (count === 3) {
                render(results);
            }
        };

        function render() {
            // TODO
        }

        var fs = require('fs');
        // connect to db
        var db = null;

        // template path string
        var template_path = null;
        fs.readFile(template_path, 'utf-8', function (err, template) {
            done('template', template);
        });

        // Structured Query Language
        var sql = null;
        db.query(sql, function (err, data) {
            done('data', data);
        });

        // http medthod get limit 10 products
        var limit10 = null;
        limit10.get(function (err, resources) {
            done('resources', resources);
        });
    };

    this.partialDerivatives = function () {
        var after = function (times, callback) {
            var count = 0, results = {};
            return function (key, value) {
                results[key] = value;
                count++;
                if (count == times) {
                    callback(results);
                }
            }
        };

        // time is 3
        var times = 3;
        var done = ater(times, render);

        function render() {
            // TODO
        }
    };

    this.manyForOne = function () {
        var after = function (times, callback) {
            var count = 0, results = {};
            return function (key, value) {
                results[key] = value;
                count++;
                if (count == times) {
                    callback(results);
                }
            }
        };

        var times = 3;
        var emitter = require('events').EventEmitter;
        var done = after(times, render);
        var other = after(times, render);

        emitter.on('done', done);
        emitter.on('done', other);

        function render() {
            // TODO
        }
    };

    this.proxy = function () {
        function EventProxy() {

        }

        var proxy = new EventProxy();

        proxy.all('template', 'data', 'resources', function (templete, data, resources) {
            // TODO
        });

        var fs = require('fs');

        // connect to db
        var db = null;

        // template path string
        var template_path = null;
        fs.readFile(template_path, 'utf-8', function (err, template) {
            proxy.emit('template', template);
        });

        // Structured Query Language
        var sql = null;
        db.query(sql, function (err, data) {
            proxy.emit('data', data);
        });

        // http medthod get limit 10 products
        var limit10 = null;
        limit10.get(function (err, resources) {
            proxy.emit('resources', resources);
        });
    };

    this.after = function () {
        function EventProxy() {

        }

        var proxy = new EventProxy();

        proxy.after('data', 10, function (datas) {
            // TODO
        });
    };

    this.backbone = function () {
        //    Trigger an event, firing all bound callbacks, Callbacks are passed the
        //    same arguments as `trigger` is, apart from the event name.
        //    Listening for `"all"` passes the true event name as the first argument
        var trigger = function (eventName) {
            var list, calls, ev, callback, args;
            var both = 2;

            if (!(calls = this._callback)) {
                return this;
            }

            while (both--) {
                ev = both ? eventName : 'all';
                if (list = calls[ev]) {
                    for (var i = 0, length = list.length; i < length; i++) {
                        if (!(callback = list[i])) {
                            list.splice(i, 1);
                            i--;
                            length--;
                        } else {
                            args = both ? Array.prototype.slice.call(arguments, 1) : arguments;
                            callback[0].apply(callback[1] || this, args);
                        }
                    }
                }
            }
            return this;
        }
    };

    this.errorEventProxyOld = function () {
        var fs = require('fs');
        /* db connect*/
        var db = null;

        exports.getContent = function (callback) {
            var ep = new EventProxy();
            ep.all('tpl', 'data', function (tpl, data) {
                callback(null, {template: tpl, data: data});
            });

            ep.bind('error', function (err) {
                ep.unbind();
                callback(err);
            });

            fs.readFile('template.tpl', 'utf-8', function (err, content) {
                if (err) {
                    return ep.emit('error', err);
                }
            });

            db.get('some sql', function (err, result) {
                if (err) {
                    return ep.emit('error', err);
                }
                ep.emit('data', result);
            });

            function EventProxy() {

            }
        }
    };

    this.errorEventProxy = function () {
        var fs = require('fs');
        /* db connect*/
        var db = null;

        exports.getContent = function (callback) {
            var ep = new EventProxy();
            ep.all('tpl', 'data', function (tpl, data) {
                callback(null, {template: tpl, data: data});
            });

            ep.fail(callback);

            fs.readFile('template.tpl', 'utf-8', ep.done('tpl'));

            db.get('some sql', ep.done('data'));

            function EventProxy() {

            }
        }
    }
}